/*
 * epollserver.cpp
 *
 *  Created on: 2017-10-1
 *      Author: hxh
 */

#include "epollserver.h"
#include <string.h>
#include "Parse.h"
#include <arpa/inet.h>
#include "DevManager.h"

epoll_server::epoll_server()
{
    m_listen_sock = 0;
    m_epoll_fd = 0;
    m_max_count = 0;
    m_epoll_events = NULL;
}

epoll_server::~epoll_server()
{
    if (m_listen_sock > 0)
    {
        close(m_listen_sock);
    }

    if (m_epoll_fd > 0)
    {
        close(m_epoll_fd);
    }
}




bool epoll_server::init(const char* ip, int port , int sock_count)
{
    m_max_count = sock_count;
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = inet_addr(ip);

    m_listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if(m_listen_sock == -1)
    {
    	perror("socket()");
        return false;
    }

    if(bind(m_listen_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
    {
    	perror("bind()");
        return false;
    }

    if(listen(m_listen_sock, 5) == -1)
    {
    	perror("listen()");
        return false;
    }

    m_epoll_events = new struct epoll_event[sock_count];
    if (m_epoll_events == NULL)
    {
        return false;
    }

    m_epoll_fd = epoll_create(sock_count);
    struct epoll_event ev;
    ev.data.fd = m_listen_sock;
    ev.events  = EPOLLIN;
    epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_listen_sock, &ev);
    return true;
}

//接收新的客户端sock，并返回，同时把心的客户端添加到epoll的监听列表里面
int epoll_server::accept_new_client()
{
    sockaddr_in client_addr;
    memset(&client_addr, 0, sizeof(client_addr));
    socklen_t clilen = sizeof(struct sockaddr);
    int new_sock = accept(m_listen_sock, (struct sockaddr*)&client_addr, &clilen);

    struct epoll_event ev;
    ev.data.fd = new_sock;
    ev.events  = EPOLLIN;
    epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, new_sock, &ev);
    return new_sock;
}

int epoll_server::recv_data(int sock, char* recv_buf)
{
    char buf[1024] = {0};
    int len = 0;
    int ret = 0;
    while(ret >= 0)
    {
        ret = recv(sock, buf, sizeof(buf), 0);
        if(ret <= 0)
        {
            struct epoll_event ev;
            ev.data.fd = sock;
            ev.events  = EPOLLERR;
            epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, sock, &ev);
            close(sock);
            break;
        }
        else if(ret < 1024)
        {
            memcpy(recv_buf, buf, ret);
            len += ret;
            struct epoll_event ev;
            ev.data.fd = sock;
            ev.events  = EPOLLOUT;
            epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, sock, &ev);
            break;
        }
        else
        {
            memcpy(recv_buf, buf, sizeof(buf));
            len += ret;
        }
    }

    return ret <= 0 ? ret : len;
}

int epoll_server::send_data(int sock, char* send_buf, int buf_len)
{
    int len = 0;
    int ret = 0;
    while(len < buf_len)
    {
        ret = send(sock, send_buf + len, 1024, 0);
        if(ret <= 0)
        {
            struct epoll_event ev;
            ev.data.fd = sock;
            ev.events  = EPOLLERR;
            epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, sock, &ev);
            close(sock);
            break;
        }
        else
        {
            len += ret;
        }

        if(ret < 1024)
        {
            break;
        }
    }

    if(ret > 0)
    {
        struct epoll_event ev;
        ev.data.fd = sock;
        ev.events  = EPOLLIN;
        epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, sock, &ev);
    }

    return ret <= 0 ? ret : len;
}

int epoll_server::epoll_server_wait(int time_out)
{
    int nfds = epoll_wait(m_epoll_fd, m_epoll_events, m_max_count, time_out);
    return  nfds;
}

void epoll_server::run(int time_out)
{
    char recv_buf[65535] = {0};
    //char send_buf[65535] = {0};
    while(1)
    {
        int ret = epoll_server_wait(time_out);
        if(ret == 0)
        {
            //cout<<"epoll_server_wait() time out"<<endl;
            continue;
        }
        else if(ret == -1)
        {
        	perror("epoll_server_wait() err");
        }
        else
        {
            for(int i = 0; i < ret; i++)
            {
                if(m_epoll_events[i].data.fd == m_listen_sock)
                {
                    if(m_epoll_events[i].events & EPOLLIN)
                    {
                        accept_new_client();
                    }
                }
                else
                {
                    if(m_epoll_events[i].events & EPOLLIN)  //有数据可以读
                    {
                    	memset(recv_buf,0,65535);
                        //int recv_count = recv_data(m_epoll_events[i].data.fd, recv_buf);
                        int recv_count = read(m_epoll_events[i].data.fd, recv_buf, 65535);
                        if(recv_count <= 0)
                        {
                        	cout<< "socket_" << m_epoll_events[i].data.fd << "close... read() = 0" << endl;
                        	int sock = m_epoll_events[i].data.fd;
                        	struct epoll_event ev;
							ev.data.fd = sock;
							ev.events  = EPOLLERR;
							epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, sock, &ev);
							close(sock);

							DevManager::get()->removeDevice(sock);

							continue;
                        }
                        cout<<recv_buf<<endl;
                        //1这里必须很快的处理完数据，否则会出现阻塞的现象！！！

                        Parse parsedata;
					   if(!parsedata.doparse(recv_buf))
					   {
						   continue;  //TODO 解析有错误，直接跳过？
					   }
                        if(parsedata.cmd == "login")
                        {
                        	char ipaddr[32]= {0};
                        	int sockfd = m_epoll_events[i].data.fd;
                        	struct sockaddr_in sa;
                        	socklen_t addrlen = sizeof(sa);
                        	if(!getpeername(sockfd, (struct sockaddr*)&sa, &addrlen))
                        	{
                        		snprintf(ipaddr,32,"%s:%d",inet_ntoa(sa.sin_addr),ntohs(sa.sin_port));
                        		cout << parsedata.tx_hid << "_" << sockfd << "@" << ipaddr <<endl;
                        	}

                        	//处理登录
                        	Device *device = new Device (sockfd, parsedata.tx_hid);
                        	device->setIpaddr(ipaddr);
                        	DevManager::get()->update(device);
                        	device->sendack(parsedata.index);
                        }
                        else if(parsedata.cmd == "tx")
                        {
                        	//在在线列表里面搜索目标设备，如果存在就发送数据过去。
                        	Device * device = DevManager::get()->getdevice(parsedata.rx_hid);
                        	if(device)
                        	{
                        		int ret = device->sendmsg(parsedata.msg);
                        		if(ret != parsedata.msg.length())
                        		{
                        			perror("write()");
                        			DevManager::get()->removeDevice(parsedata.rx_hid);//没有fd，只有HID，这种情况删除
                        		}
                        	}
                        	//更新一下发送者的时间
                        	device = DevManager::get()->getdevice(parsedata.tx_hid);
							if(device)
							{
								device->updateStatus();
								device->sendack(parsedata.index);
							}
                        }
                        else if(parsedata.cmd == "getlist")  //这是web或者app获取在线列表等功能的接口。
						{
                        	string devlist = DevManager::get()->getlist();
                        	//cout <<"devlist："<<devlist<<endl;
                        	write(m_epoll_events[i].data.fd,devlist.c_str(),devlist.length());
						}
                        else if(parsedata.cmd=="ping")  //心跳包
                        {
                        	Device * device = DevManager::get()->getdevice(parsedata.tx_hid);
							if(device)
							{
								device->updateStatus();
								device->sendack(parsedata.index);
							}
                        }

                    }
                    else if(m_epoll_events[i].events & EPOLLOUT)  //可以写入
                    {
                        //int send_count = send_data(m_epoll_events[i].data.fd, send_buf, strlen(send_buf));
                        //memset(send_buf, 0, sizeof(send_buf));
                    	cout<<"epoll out"<<endl;
                    }

                }
            }
        }
    }
}

